﻿using Blm.PgsqlDriver.Helpers;
using Blm.RabbitMQ.MessageQueue;
using Blm.Utils.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.Data;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.DtoModel.RabbitMq;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.Repository.Interface.Rs;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Service.Sys;
using VisionCloud.Utility;
using VisionCloud.Utility.Redis;

namespace VisionCloud.Service.Ms
{
    public class ProjectService
    {
        private OperatorInfo TokenModel => OperatorProvider.Get();

        public IUnitOfWork UnitOfWork { get; set; }

        public IMsProjectRepository MsProjectRepository { get; set; }

        public IMsHouseMapRepository MsHouseMapRepository { get; set; }

        public ISysUserProjectRepository SysUserProjectRepository { get; set; }

        public IMsPointTypeRepository MsPointTypeRepository { get; set; }

        public IMsProjectStandardRepository MsProjectStandardRepository { get; set; }

        public IMsProjectStandardMeasureItemValueRepository MsProjectStandardMeasureItemValueRepository { get; set; }

        public IMsProjectStandardMeasureItemRepository MsProjectStandardMeasureItemRepository { get; set; }

        public IMsPointTypeMeasureItemRepository MsPointTypeMeasureItemRepository { get; set; }

        public IMsUserToProjectRepository MsUserToProjectRepository { get; set; }

        public ISysUserRepository SysUserRepository { get; set; }

        public IMsProjectEditLogRepository MsProjectEditLogRepository { get; set; }

        public IMsTaskRepository MsTaskRepository { get; set; }

        public ILogger<ProjectService> Logger { get; set; }

        public UserProjectService UserProjectService { get; set; }

        public MsProjectEditLogService MsProjectEditLogService { get; set; }

        public StandardService StandardService { get; set; }

        public UserToProjectMessageService UserToProjectMessageService { get; set; }

        public SmsService SmsService { get; set; }

        public IRsWorkOrderMapRepository RsWorkOrderMapRepository { get; set; }

        public IRabbitMQProducer RabbitMQProducer { get; set; }

        /// <summary>
        /// 检查户型楼层的数值范围
        /// </summary>
        /// <param name="details"></param>
        public void CheckDetail(List<Detail> details)
        {
            if (details == null || details.Count <= 0)
            {
                throw new ArgumentException("YB0080".SLocalize());
            }
            foreach (var el in details)
            {
                #region 层数校验

                if (el.Floor.ToInt32(out int result) == false
                    || el.Floor.ToInt32() < 1
                    || el.Floor.ToInt32() > 200)
                {
                    throw new OperationException("YB0074".SLocalize());
                }

                #endregion 层数校验

                #region 户数校验

                if (el.HouseHolds.ToInt32(out result) == false
                    || el.HouseHolds.ToInt32() < 1
                    || el.HouseHolds.ToInt32() > 99)
                {
                    throw new OperationException("YB0075".SLocalize());
                }

                #endregion 户数校验

                #region 交付类型校验

                if (string.IsNullOrWhiteSpace(el.Standard))
                {
                    throw new ArgumentException("YB0076".SLocalize());
                }

                if (!string.Equals(el.Standard, "GX00009".SLocalize()) && !string.Equals(el.Standard, "GX00010".SLocalize()))
                {
                    Logger.LogError(el.Standard + ";" + "GX00009".SLocalize() + ";" + "GX00010".SLocalize());
                    throw new ArgumentException("YB0078".SLocalize());
                }

                #endregion 交付类型校验

                #region 楼栋号校验

                string pattern = @"^[\u4e00-\u9fa5_a-zA-Z0-9]+$";//排除特殊字符

                if (string.IsNullOrWhiteSpace(el.Building) || !Regex.Match(el.Building, pattern).Success)
                {
                    throw new ArgumentException("YB0015".SLocalize());
                }

                // 和前端保持一直，限制最长5位楼栋号
                if (el.Building.Length > 5)
                {
                    throw new ArgumentException("YB0079".SLocalize());
                }

                #endregion 楼栋号校验
            }
        }

        /// <summary>
        /// 分页取项目数据
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<ApiPageResult> GetPage(MsProjectCondition condition)
        {
            var result = await MsProjectRepository.GetPage(condition);  // 分页取项目数据
            List<MsProjectDto> list = result.PageData as List<MsProjectDto>;
            GetHasChangelog(list);
            result.PageData = list;
            return result;
        }

        /// <summary>
        /// 获取项目列表
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<ApiPageResult> GetList(MsProjectCondition condition)
        {
            var result = await MsProjectRepository.GetList(condition);  // 分页取项目数据
            List<MsProjectDto> list = result.PageData as List<MsProjectDto>;
            GetHasChangelog(list);
            result.PageData = list;
            return result;
        }

        /// <summary>
        /// 获取已改变记录
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private List<MsProjectDto> GetHasChangelog(List<MsProjectDto> list)
        {
            if (list == null || list.Count == 0)
                return list;
            Dictionary<Guid, int> hasChangeLog = MsProjectEditLogRepository.HasChangeLog(list.Select(x => x.ProjectId).ToList());
            foreach (var project in list)
            {
                project.HasChangelog = hasChangeLog.ContainsKey(project.ProjectId);
            }
            return list;
        }

        private List<string> GetAllowlist()
        {
            List<string> allowlist = new List<string>
            {
                "40a68f76-1460-40f6-b8f2-25d133f200ca",
                "ad9c6745-a379-4e1d-a36d-e6d695d2758f",
                "c023f032-a36c-4d24-b0ba-e874426844a6"
            };
            return allowlist;
        }

        /// <summary>
        /// 获取当前用户参有权限的项目
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<ApiPageResult> GetProjectInfo(MsProjectCondition condition)
        {
            if (string.IsNullOrWhiteSpace(condition.ProjectId.ToString()))
            {
                throw new OperationException("YB0081".SLocalize());
            }
            // 账号：18229940273和18811127360属于白名单
            if (this.GetAllowlist().Contains(OperatorProvider.Get()?.YunUserGuid.ToString()))
            {
                condition.Allowlist = true;
            }

            var projectList = await MsProjectRepository.GetPublishProjects(condition);
            if (projectList?.Count == 0)
            {
                throw new OperationException("YB0082".SLocalize());
            }

            var data = new ApiPageResult()
            {
                PageData = null
            };

            string paras = string.Empty;
            foreach (var item in projectList)
            {
                paras += $"'{item.ProjectId}',";
            }

            paras = paras.Substring(0, paras.Length - 1);

            // 获取已上传报告的项目信息
            string sql = string.Format(@"SELECT DISTINCT
	                                       ""ProjectId"",
	                                       ""BuildingName"",
	                                       ""FloorName""
                                         FROM
	                                       ""CSMSTask""
                                         WHERE
	                                       ""ProjectId"" IN ({0})
                                         ORDER BY
	                                       ""ProjectId"",
	                                       ""BuildingName"",
	                                       ""FloorName""", paras);

            var floorList = await PgSqlHelper.QueryListAsync<ProjectFloorDto>(sql);
            List<MsProjectDtoExt> projectDtoExts = new List<MsProjectDtoExt>(); // 简化返回dto对象
            if (floorList.Count > 0)
            {
                foreach (var item in projectList)
                {
                    var list = floorList.Where(p => p.ProjectId == item.ProjectId).ToList();
                    if (list.Count == 0)
                        continue;

                    string buildingName = string.Empty;
                    MeasuredFloors mf = null;
                    List<MeasuredFloors> measuredFloorses = new List<MeasuredFloors>();
                    // 获取每个项目中已测楼栋和楼层信息
                    foreach (var row in list)
                    {
                        if (row.BuildingName != buildingName)
                        {
                            mf = new MeasuredFloors()
                            {
                                BuildingName = row.BuildingName
                            };
                            buildingName = row.BuildingName;
                            measuredFloorses.Add(mf);
                        }
                        mf?.FloorsName.Add(row.FloorName);
                    }

                    var copyData = item.CopyTo<MsProjectDtoExt>();
                    copyData.MeasuredFloors = measuredFloorses;
                    projectDtoExts.Add(copyData);
                }
            }
            data.Total = projectDtoExts.Count;
            data.PageSize = projectDtoExts.Count;
            data.PageData = projectDtoExts;
            return data;
        }

        /// <summary>
        /// 项目项目编号
        /// </summary>
        /// <param name="companyGuid"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<string> GetProjectNmb(Guid companyGuid)
        {
            try
            {
                int times = 0;
                while (times < 3)
                {
                    List<NpgsqlParameter> paras = new List<NpgsqlParameter>();
                    var selectSql = $@"select * from ""MsProjectNum"" where ""CompanyGuid"" = '{companyGuid}'";
                    var info = await PgSqlHelper.QueryOneAsync<MsProjectNum>(selectSql);
                    if (info == null)
                    {
                        MsProjectNum mp = new MsProjectNum();
                        mp.CompanyGuid = companyGuid;
                        mp.CurrentMaxProjectNum = 1;
                        mp.UpdateDateTime = DateTime.Now;
                        mp.LockSignal = Guid.NewGuid();
                        try
                        {
                            paras.Add(new NpgsqlParameter("@CompanyGuid", mp.CompanyGuid));
                            paras.Add(new NpgsqlParameter("@CurrentMaxProjectNum", mp.CurrentMaxProjectNum));
                            paras.Add(new NpgsqlParameter("@UpdateDateTime", mp.UpdateDateTime));
                            paras.Add(new NpgsqlParameter("@LockSignal", mp.LockSignal));

                            var insertSql = @"INSERT INTO ""MsProjectNum"" (""CompanyGuid"",""CurrentMaxProjectNum"",""UpdateDateTime"",""LockSignal"")
                                              VALUES (@CompanyGuid, @CurrentMaxProjectNum, @UpdateDateTime, @LockSignal)";

                            var insertresult = await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, insertSql, paras.ToArray());
                            if (insertresult != 1)
                            {
                                times = times + 1;
                                continue;
                            }
                            else
                            {
                                return 1.ToString().PadLeft(6, '0');
                            }
                        }
                        catch (Exception ex)
                        {
                            if (ex.Message.Contains("duplicate key"))
                            {
                                times = times + 1;
                                continue;
                            }
                        }
                    }
                    else
                    {
                        int newProjectNum = info.CurrentMaxProjectNum + 1;
                        var updateSql = @"update  ""MsProjectNum"" set ""CurrentMaxProjectNum"" = @CurrentMaxProjectNum,""UpdateDateTime"" = @UpdateDateTime,""LockSignal"" = @NewLockSignal
                                          where ""CompanyGuid""= @CompanyGuid and ""LockSignal""= @LockSignal";

                        paras.Add(new NpgsqlParameter("@CompanyGuid", info.CompanyGuid));
                        paras.Add(new NpgsqlParameter("@CurrentMaxProjectNum", newProjectNum));
                        paras.Add(new NpgsqlParameter("@UpdateDateTime", DateTime.Now));
                        paras.Add(new NpgsqlParameter("@LockSignal", info.LockSignal));
                        paras.Add(new NpgsqlParameter("@NewLockSignal", Guid.NewGuid()));

                        var updateResult = await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, updateSql, paras.ToArray());
                        if (updateResult != 1)
                        {
                            times = times + 1;
                            continue;
                        }
                        else
                            return newProjectNum.ToString().PadLeft(6, '0');
                    }
                }
                if (times == 3)
                {
                    throw new OperationException("YB0084".SLocalize());
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex.Message, ex);
                //throw new Exception("YB0084".SLocalize());
            }
            return null;
        }

        /// <summary>
        /// 添加项目
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<Guid> Add(MsProjectDto model)
        {
            // 校验项目信息
            VerifyProject(model);

            bool exist = await ProjectIsExist(model.Name);
            if (exist)
                throw new OperationException("YB0084".SLocalize(model.Name));
            if (model.DetailsInfo != null)
            {
                bool isRepeat = model.DetailsInfo.GroupBy(i => i.Building).Where(g => g.Count() > 1).Any();
                if (isRepeat)
                    throw new OperationException("YB0085".SLocalize());
            }
            CheckDetail(model.DetailsInfo);
            //var location = await AddressHelper.GetLocationFromAddress($"{model.Province}{model.City}{model.Town}{model.Address}");
            model.Details = model.DetailsInfo == null ? "" : JsonConvert.SerializeObject(model.DetailsInfo);
            var entity = model.CopyTo<MsProject>();
            entity.ProjectId = Guid.NewGuid();
            entity.CreatedBy = OperatorProvider.Get().Id;
            entity.CreatedDate = DateTime.Now;
            entity.LastUpdatedBy = OperatorProvider.Get().Id;
            entity.LastUpdatedDate = DateTime.Now;
            entity.CompanyGuid = OperatorProvider.Get().CompanyGuid;
            entity.ProjectNo = OperatorProvider.Get().OrgCode + '-' + await GetProjectNmb(entity.CompanyGuid);
            entity.ProjectVersion = 0;
            entity.IsCanPull = false;
            //entity.Latitude = location.lat;
            //entity.Longitude = location.lng;
            //新建项目默认将管理员加入SysUserProject表关系中
            var userProject = new SysUserProject
            {
                UserProjectId = Guid.NewGuid(),
                ProjectId = entity.ProjectId,
                UserId = OperatorProvider.Get().Id,
            };
            entity.SysUserProject.Add(userProject);
            var utp = new MsUserToProject()
            {
                CreatedBy = OperatorProvider.Get().Id,
                CreatedDate = DateTime.Now,
                YunProjectGuid = entity.ProjectId,
                YunUserGuid = OperatorProvider.Get().Id,
                MsUserToProjectId = Guid.NewGuid()
            };
            MsUserToProjectRepository.Add(utp);
            MsProjectRepository.Add(entity);
            var syncReport = new MsDataSnyc
            {
                Id = Guid.NewGuid(),
                ItemId = entity.ProjectId,
                ItemType = "project",
                Priority = 3,
                NeedUpload = true
            };

            var standardList = StandardService.GetProjectStandardModelTemplateList();
            foreach (var item in standardList)
            {
                MsProjectStandard mps = new MsProjectStandard();
                {
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Content = item.Content;
                    mps.Description = item.Description;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.Stage = item.Stage;
                    mps.Template = item.Template;
                    mps.Title = item.Title;
                    mps.Code = item.Code;
                    mps.MsProjectStandardId = Guid.NewGuid();
                    mps.Version = item.Version;
                }
                MsProjectStandardRepository.Add(mps);
            }
            var ProjectStandardMeasureItems = await MsProjectStandardMeasureItemRepository.GetTemplateList();
            foreach (var item in ProjectStandardMeasureItems)
            {
                MsProjectStandardMeasureItem mps = new MsProjectStandardMeasureItem();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Code = item.Code;
                    mps.CreatedBy = OperatorProvider.Get().Id;
                    mps.CreatedDate = DateTime.Now;
                    mps.HasDesignValue = item.HasDesignValue;
                    mps.Id = item.Id;
                    mps.IsDeleted = item.IsDeleted;
                    mps.LastUpdatedBy = OperatorProvider.Get().Id;
                    mps.LastUpdatedDate = DateTime.Now;
                    mps.MsProjectStandardMeasureItemId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.SupportCraft = item.SupportCraft;
                    mps.SupportStandard = item.SupportStandard;
                    mps.Title = item.Title;
                    mps.Type = item.Type;
                }
                MsProjectStandardMeasureItemRepository.Add(mps);
            }

            var MsProjectStandardMeasureItemValues = await MsProjectStandardMeasureItemValueRepository.GetTemplateList();
            var projectStandardMeasureItemList = new List<MsProjectStandardMeasureItemValue>();
            foreach (var item in MsProjectStandardMeasureItemValues)
            {
                MsProjectStandardMeasureItemValue mps = new MsProjectStandardMeasureItemValue();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Id = item.Id;
                    mps.Key = item.Key;
                    mps.LeftValue = item.LeftValue;
                    mps.MsProjectStandardMeasureItemValueId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.RightValue = item.RightValue;
                    mps.SeqNo = item.SeqNo;
                    mps.Title = item.Title;
                    mps.Unit = item.Unit;
                }
                projectStandardMeasureItemList.Add(mps);
            }
            MsProjectStandardMeasureItemValueRepository.AddRange(projectStandardMeasureItemList);

            var MsPointTypeMeasureItems = await MsPointTypeMeasureItemRepository.GetTemplateList();
            var PointMeasureItemList = new List<MsPointTypeMeasureItem>();
            foreach (var item in MsPointTypeMeasureItems)
            {
                MsPointTypeMeasureItem mps = new MsPointTypeMeasureItem();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Id = item.Id;
                    mps.IsChecked = item.IsChecked;
                    mps.MsPointTypeId = item.MsPointTypeId;
                    mps.MsPointTypeMeasureItemId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                }
                PointMeasureItemList.Add(mps);
            }
            MsPointTypeMeasureItemRepository.AddRange(PointMeasureItemList);

            var MsPointTypeItems = await MsPointTypeRepository.GetTemplateList();
            var pointTypeList = new List<MsPointType>();
            foreach (var item in MsPointTypeItems)
            {
                MsPointType mps = new MsPointType();
                {
                    mps.Id = item.Id;
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.CreatedBy = OperatorProvider.Get().Id;
                    mps.CreatedDate = DateTime.Now;
                    mps.IsDeleted = item.IsDeleted;
                    mps.LastUpdatedBy = OperatorProvider.Get().Id;
                    mps.LastUpdatedDate = DateTime.Now;
                    mps.MsPointTypeId = Guid.NewGuid();
                    mps.Name = item.Name;
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.VersionTypeName = item.VersionTypeName;
                    mps.Type = item.Type;
                }
                pointTypeList.Add(mps);
            }
            MsPointTypeRepository.AddRange(pointTypeList);
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】成功添加了项目：[{entity.Name}], 项目ID：[{entity.ProjectId}]");

            //清除项目成员缓存
            MsTaskRepository.RemoveUserProjects();

            //向数据中心添加项目
            await RabbitMQProducer.SendAsync(new ProjectAddDto { ProjectId = entity.ProjectId });

            return entity.ProjectId;
        }

        /// <summary>
        /// 兼容旧项目修改时获取最新项目阶段数据
        /// </summary>
        private async Task AddStandard(MsProjectDto model)
        {
            Guid allowCompanyId = OperatorProvider.Get().CompanyGuid;
            var userProject = new SysUserProject
            {
                UserProjectId = Guid.NewGuid(),
                ProjectId = model.ProjectId,
                UserId = OperatorProvider.Get().Id,
            };

            // 当前标准库拥有的项目阶段
            var standardList = StandardService.GetProjectStandardModelTemplateList();

            // 当前项目拥有的项目阶段
            var currentProjectStandard = StandardService.GetListByProject(model.ProjectId);

            //standardList = standardList.Where(x => !currentProjectStandard.Exists(y => y.ProjectStandardId == x.ProjectStandardId)).ToList();
            var ids = currentProjectStandard.Select(y => y.ProjectStandardId).ToList();
            standardList = standardList.Where(x => !ids.Contains(x.ProjectStandardId)).ToList();
            if (standardList == null || standardList.Count == 0)
            {
                // 当前已获取最新项目阶段数据；
                return;
            }

            foreach (var item in standardList)
            {
                MsProjectStandard mps = new MsProjectStandard();
                {
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Content = item.Content;
                    mps.Description = item.Description;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.Stage = item.Stage;
                    mps.Template = item.Template;
                    mps.Title = item.Title;
                    mps.Code = item.Code;
                    mps.MsProjectStandardId = Guid.NewGuid();
                }
                MsProjectStandardRepository.Add(mps);
            }
            var ProjectStandardMeasureItems = await MsProjectStandardMeasureItemRepository.GetTemplateList();
            foreach (var item in ProjectStandardMeasureItems.Where(x => !ids.Contains(x.ProjectStandardId)))
            {
                MsProjectStandardMeasureItem mps = new MsProjectStandardMeasureItem();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Code = item.Code;
                    mps.CreatedBy = OperatorProvider.Get().Id;
                    mps.CreatedDate = DateTime.Now;
                    mps.HasDesignValue = item.HasDesignValue;
                    mps.Id = item.Id;
                    mps.IsDeleted = item.IsDeleted;
                    mps.LastUpdatedBy = OperatorProvider.Get().Id;
                    mps.LastUpdatedDate = DateTime.Now;
                    mps.MsProjectStandardMeasureItemId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.SupportCraft = item.SupportCraft;
                    mps.SupportStandard = item.SupportStandard;
                    mps.Title = item.Title;
                    mps.Type = item.Type;
                }
                MsProjectStandardMeasureItemRepository.Add(mps);
            }

            var MsProjectStandardMeasureItemValues = await MsProjectStandardMeasureItemValueRepository.GetTemplateList();
            foreach (var item in MsProjectStandardMeasureItemValues.Where(x => !ids.Contains(x.ProjectStandardId)))
            {
                MsProjectStandardMeasureItemValue mps = new MsProjectStandardMeasureItemValue();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Id = item.Id;
                    mps.Key = item.Key;
                    mps.LeftValue = item.LeftValue;
                    mps.MsProjectStandardMeasureItemValueId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                    mps.RightValue = item.RightValue;
                    mps.SeqNo = item.SeqNo;
                    mps.Title = item.Title;
                    mps.Unit = item.Unit;
                }
                MsProjectStandardMeasureItemValueRepository.Add(mps);
            }

            var MsPointTypeMeasureItems = await MsPointTypeMeasureItemRepository.GetTemplateList();
            foreach (var item in MsPointTypeMeasureItems.Where(x => !ids.Contains(x.ProjectStandardId)))
            {
                MsPointTypeMeasureItem mps = new MsPointTypeMeasureItem();
                {
                    mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                    mps.Id = item.Id;
                    mps.IsChecked = item.IsChecked;
                    mps.MsPointTypeId = item.MsPointTypeId;
                    mps.MsPointTypeMeasureItemId = Guid.NewGuid();
                    mps.ProjectGuid = userProject.ProjectId;
                    mps.ProjectStandardId = item.ProjectStandardId;
                }
                MsPointTypeMeasureItemRepository.Add(mps);
            }

            // 取模板中设置站点类型
            var pointTypeItemsTemplate = await MsPointTypeRepository.GetTemplateList();
            // 取当前项目中设置站点类型
            var currentPointTypeItems = await MsPointTypeRepository.GetListByProjectId(model.ProjectId, false);
            // 当前模板拥有站点类型Id
            var pointIds = pointTypeItemsTemplate.Select(y => y.Id).ToList();
            // 取项目中新增的站点对象
            var newAddPointType = currentPointTypeItems.Where(x => !pointIds.Contains(x.Id)).ToList();
            // 存在新增站点类型
            if (newAddPointType?.Count > 0)
            {
                var templatePointTypeMeasureItem = await MsPointTypeMeasureItemRepository.GetTemplateList();

                foreach (var item in standardList)
                {
                    var template = templatePointTypeMeasureItem.Where(x => x.ProjectStandardId == item.ProjectStandardId
                    && x.MsPointTypeId == "e8a56b02-0fe5-4db2-9c01-fc937eb86eb1".ToGuid()).ToList();
                    if (template?.Count() == 0)
                    {
                        return;
                    }
                    foreach (var pointTypeItem in newAddPointType)
                    {
                        foreach (var t in template)
                        {
                            MsPointTypeMeasureItem mps = new MsPointTypeMeasureItem();
                            {
                                mps.CompanyGuid = OperatorProvider.Get().CompanyGuid;
                                mps.Id = t.Id;
                                mps.IsChecked = t.IsChecked;
                                mps.MsPointTypeId = pointTypeItem.Id;   // 站点类型Id
                                mps.MsPointTypeMeasureItemId = Guid.NewGuid();
                                mps.ProjectGuid = userProject.ProjectId;
                                mps.ProjectStandardId = item.ProjectStandardId;
                            }
                            MsPointTypeMeasureItemRepository.Add(mps);
                        }
                        Logger.LogInformation($"新增站点类型：项目Id {userProject.ProjectId}, {pointTypeItem.Name}, {template.Count} ");
                    }
                }
            }

            UnitOfWork.SaveChangesAsync().GetAwaiter().GetResult();
        }

        /// <summary>
        /// 更新项目
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task Update(MsProjectDto model)
        {
            // 校验项目信息
            VerifyProject(model);

            await CheckExsitedTask(model);
            CheckDetail(model.DetailsInfo);

            bool exist = false;
            exist = await ProjectIsExistNotSelf(model.ProjectId, model.Name);
            if (exist)
                throw new OperationException("YB0086".SLocalize(model.Name));
            //检查发布锁
            var project = await MsProjectRepository.GetByIdAsync(model.ProjectId);
            if (project == null)
                throw new OperationException("YB0087".SLocalize());
            if (project.PubliceDetailsCount > model.DetailsInfo.Count)
                throw new OperationException("YB0088".SLocalize());
            if (project.PubliceDate.HasValue)
            {
                List<Detail> tl = JsonConvert.DeserializeObject<List<Detail>>(project.Details);
                for (int i = 0; i < project.PubliceDetailsCount; i++)
                {
                    if (!tl[i].Equals(model.DetailsInfo[i]))
                        throw new OperationException("YB0088".SLocalize());
                }
            }
            model.Details = JsonConvert.SerializeObject(model.DetailsInfo);
            //版本号增加1
            var ProjectVersion = project.ProjectVersion;
            MsProjectRepository.Update(t => t.ProjectId == model.ProjectId,
                    d =>
                    {
                        //待更新字段
                        d.Name = model.Name;
                        d.Description = model.Description;
                        d.MapPoint = model.MapPoint;
                        d.Stage = model.Stage;
                        d.Standard = model.Standard;
                        d.Address = model.Address;
                        d.Province = model.Province;
                        d.City = model.City;
                        d.Town = model.Town;
                        d.Details = model.Details;
                        d.LastUpdatedBy = OperatorProvider.Get().Id;
                        d.LastUpdatedDate = DateTime.Now;
                        d.ProjectVersion = ProjectVersion + 1;
                        d.IsCanPull = false;
                        d.RegionalCompany = model.RegionalCompany;
                        d.ProjectManager = model.ProjectManager;                  // 项目经理
                    });

            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】更新了项目：[{model.Name}], 项目ID：[{model.ProjectId}]");
        }

        /// <summary>
        /// 校验新项目数据
        /// </summary>
        private void VerifyProject(MsProjectDto model)
        {
            if (string.IsNullOrWhiteSpace(model.Name))
            {
                throw new ArgumentException("YB0089".SLocalize());
            }

            if (model.Name.IsSpecialChars())
            {
                throw new ArgumentException(@"YB0090".SLocalize());
            }

            if (model.Name.Length > 20)
            {
                throw new OperationException(@"YB0091".SLocalize());
            }

            if (string.IsNullOrWhiteSpace(model.Address))
            {
                throw new ArgumentException(@"YB0092".SLocalize());
            }

            if (model.Address.Length > 50)
            {
                throw new ArgumentException(@"YB0093".SLocalize());
            }
        }

        /// <summary>
        /// 检查用户的权限：公司管理员和项目管理员，具有项目新增/修改/删除权限；
        /// </summary>
        public void CheckUserAccess()
        {
            string roleName = TokenModel.RoleNameList;
            if (!roleName.Contains("公司管理员") && !roleName.Contains("测量管理员"))
            {
                throw new OperationException("YB0094".SLocalize());
            }
        }

        /// <summary>
        /// 删除项目
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public async Task Delete(Guid projectId)
        {
            if (projectId == Guid.Empty)
                throw new OperationException("YB0095".SLocalize());

            //modified by 徐文清, on 2021-11-23. 新需求规定测量管理员以上可以删除已发布过得项目，但要发短信通知相关人员

            var projEntity = MsProjectRepository.GetById(projectId);
            projEntity.ProjectVersion += 1;
            projEntity.IsNeedTipDel = projEntity.IsPullByClient;
            MsProjectRepository.Remove(projEntity);

            await RemoveUserRelation(projectId);
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】删除项目：[{projectId}]");

            //清除项目成员缓存
            MsTaskRepository.RemoveUserProjects();

            //发送队列消息，重新统计和该项目有关的设备的统计数据
            await RabbitMQProducer.SendAsync(new MsDevicePushDto
            {
                Type = 2,
                ProjectId = projectId
            });
        }

        /// <summary>
        /// 删除用户关联项目缓存
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public async Task DeleteProjectCache(Guid projectId)
        {
            var userProjects = await MsUserToProjectRepository.WhereAsync(i => i.YunProjectGuid == projectId).ConfigureAwait(false);
            var companyGuid = OperatorProvider.Get().CompanyGuid.ToString();
            var userIds = userProjects.Select(utp => utp.YunUserGuid).ToArray();
            var managerUserInfo = SysUserRepository.Where(u => u.IsDeleted == false && u.Status == SysUser.EnumUserStatus.正常 && u.SysOrgId == companyGuid && u.RoleNameList.Contains("公司管理员")).Select(u => u).ToArray();
            var managerUser = managerUserInfo.Select(u => u.YunUserGuid).ToArray();
            userIds = userIds.Union(managerUser).ToArray();

            if (userIds != null && userIds.Count() > 0)
            {
                foreach (var id in userIds)
                {
                    await RedisHelper.Instance.StringDeleteAsync(RedisKeyConstant.ProjectVersionKey(id));
                }
            }
        }

        /// <summary>
        /// 当删除项目后发送短信通知
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="ip"></param>
        /// <returns></returns>
        public async Task<Dictionary<Guid, string>> SendMsgAfterDel(Guid projectId, string ip)
        {
            var reuslt = new Dictionary<Guid, string>();
            var projEntity = MsProjectRepository.GetById(projectId);
            var projetName = projEntity?.Name;
            //只有客户已拉取的项目，才发短信通知
            if (projetName == null || !projEntity.IsPullByClient)
            {
                return reuslt;
            }
            var id_phones = await MsUserToProjectRepository.GetRefUserPhonesByProjId(projectId);
            if (id_phones == null || id_phones.Count < 1)
            {
                return reuslt;
            }
            var opName = OperatorProvider.Get().Name;

            foreach (var item in id_phones)
            {
                try
                {
                    await SmsService.SendSms(ip,
                             item.Value, "YB0097".SLocalize(projetName, opName));
                }
                catch (Exception ex)
                {
                    Logger.LogInformation("删除项目发送短信发生错误:" + ex.Message);
                }
            }
            return id_phones;
            //id_phones.ForEach(async x => await smsService.SendSms(ip,
            //               x, $"您关联的“{projetName}”项目在云端被测量管理员/公司管理员“{opName}”删除，相关数据已全部清空，请及时连网进行数据同步"));
        }

        /// <summary>
        /// 移除项目的人员关联关系
        /// </summary>
        /// <param name="projId"></param>
        /// <returns></returns>
        public async Task RemoveUserRelation(Guid projId)
        {
            await MsUserToProjectRepository.DeleteAsync(x => x.YunProjectGuid == projId);
            await SysUserProjectRepository.DeleteAsync(y => y.ProjectId == projId);
            //await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 禁用项目
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task SetDisable(Guid projectId)
        {
            if (projectId == Guid.Empty)
                throw new OperationException("YB0095".SLocalize());
            MsProjectRepository.Update(t => t.ProjectId == projectId,
                    d =>
                    {
                        d.Status = MsProject.ProjectStatus.禁用;
                        d.LastUpdatedBy = OperatorProvider.Get().Id;
                        d.LastUpdatedDate = DateTime.Now;
                    });
            await UnitOfWork.SaveChangesAsync();
            Logger.LogInformation($"【{OperatorProvider.Get().Name}】禁用项目：[{projectId}]");
            //清除项目成员缓存
            MsTaskRepository.RemoveUserProjects();
        }

        /// <summary>
        /// 获取项目信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<MsProjectDto> GetProjectInfo(string id)
        {
            if (string.IsNullOrWhiteSpace(id))
                throw new OperationException("YB0098".SLocalize());

            var project = await MsProjectRepository.GetByIdAsync(new Guid(id));
            if (project == null)
                throw new OperationException("YB0064".SLocalize());
            if (project != null && project.IsDeleted)
                throw new OperationException("YB0099".SLocalize());

            var result = project.CopyTo<MsProjectDto>();
            result.DetailsInfo = JsonConvert.DeserializeObject<List<Detail>>(project.Details);

            return result;
        }

        /// <summary>
        /// 发布项目
        /// </summary>
        /// <param name="ip">ip</param>
        /// <param name="projectId">项目id</param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task PubliceProject(string ip, Guid projectId)
        {
            var project = await MsProjectRepository.GetByIdAsync(projectId);
            if (project == null)
                throw new OperationException("YB0087".SLocalize());
            if (string.IsNullOrEmpty(project.Details))
                throw new OperationException("YB0114".SLocalize());
            string errmsg = await MsProjectRepository.CheckHouseMapForPublice(projectId);
            if (!string.IsNullOrEmpty(errmsg))
                throw new OperationException(errmsg);
            errmsg = await MsProjectRepository.CheckHouseMapBuildingAndFloorForPublice(projectId);
            if (!string.IsNullOrEmpty(errmsg))
                throw new OperationException(errmsg);
            await RabbitMQProducer.SendAsync(new ProjectPublishDto { ProjectId = projectId });
            //发布项目写入日志---一定要在修改项目信息前做日志记录,不能使用异步
            MsProjectEditLogService.WriteProjectPublishLog(project).GetAwaiter().GetResult();
            bool IsFirstPublice = !project.PubliceDate.HasValue;
            string json = project.Details;
            JArray jarray = JArray.Parse(json);
            project.PubliceDetailsCount = jarray.Count;
            project.PubliceDate = DateTime.Now;
            project.IsCanPull = true;

            MsProjectRepository.Update(project, f => new { f.IsCanPull, f.PubliceDetailsCount, f.PubliceDate });
            var UTP = await MsUserToProjectRepository.WhereAsync(i => i.YunProjectGuid == projectId).ConfigureAwait(false);
            // 第一次创建项目没有关联用户，公司管理员也需要同步到项目
            var companyGuid = OperatorProvider.Get().CompanyGuid.ToString();
            var UTPUSRID = UTP.Select(utp => utp.YunUserGuid).ToArray();
            var managerUserInfo = SysUserRepository.Where(u => u.IsDeleted == false && u.Status == SysUser.EnumUserStatus.正常 && u.SysOrgId == companyGuid && u.RoleNameList.Contains("公司管理员")).Select(u => u).ToArray();
            var managerUser = managerUserInfo.Select(u => u.YunUserGuid).ToArray();
            UTPUSRID = UTPUSRID.Union(managerUser).ToArray();

            //g
            foreach (var managerItem in managerUserInfo)
            {
                if (!UTP.Any(i => i.YunUserGuid == managerItem.YunUserGuid))
                {
                    UTP.Add(new MsUserToProject() { YunUserGuid = managerItem.YunUserGuid, IsSendMessage = true, YunProjectGuid = project.ProjectId });
                }
            }
            if (!UTP.Any(i => i.YunUserGuid == project.CreatedBy))
            {
                UTP.Add(new MsUserToProject() { YunUserGuid = project.CreatedBy, IsSendMessage = true, YunProjectGuid = project.ProjectId });
            }
            var userInfo = await SysUserRepository.WhereAsync(i =>
                UTPUSRID.Contains(i.YunUserGuid)
                ).ConfigureAwait(false);
            await UnitOfWork.SaveChangesAsync();
            if (UTPUSRID != null)
            {
                foreach (var id in UTPUSRID)
                {
                    await RedisHelper.Instance.StringDeleteAsync(RedisKeyConstant.ProjectVersionKey(id));
                }
            }

            // 获取该项目是否有工单
            var workOrderMsg = await GetWorkOrderMessage(projectId);
            await UserToProjectMessageService.PubliceProject(userInfo, ip, project, UTP, IsFirstPublice, workOrderMsg);

            Logger.LogInformation($"【{OperatorProvider.Get().Name}】发布项目：[{projectId}]");
            //发布短信通知用户项目已经修改
        }

        /// <summary>
        /// 构造工单短信内容
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        private async Task<string> GetWorkOrderMessage(Guid projectId)
        {
            var companyGuid = OperatorProvider.Get().CompanyGuid;
            var entities = await RsWorkOrderMapRepository.GetWorkOrderMapList(projectId, companyGuid);
            if (entities == null || entities.Count < 1)
            {
                return string.Empty;
            }

            StringBuilder message = new StringBuilder();
            message.Append($"；【{entities[0].ProjectName}】");
            foreach (var item in entities)
            {
                message.Append(string.Format("YB0461".SLocalize(), item.BpsTaskId, item.BuildingName, item.FloorName, item.ProcedureName));
                message.Append("、");
            }
            // 移除末尾符合
            message = message.Remove(message.Length - 1, 1);
            return message.ToString();
        }

        /// <summary>
        /// 获取项目楼栋
        /// </summary>
        /// <returns></returns>
        public async Task<List<Detail>> GetProjectBuilding(Guid Id)
        {
            var project = await MsProjectRepository.GetByIdAsync(Id);
            if (project == null)
                throw new OperationException("YB0115".SLocalize());
            return JsonConvert.DeserializeObject<List<Detail>>(project.Details);
        }

        /// <summary>
        /// 获取获取项目下拉选项
        /// </summary>
        /// <returns></returns>
        public async Task<List<SelectItem>> GetProjectSelectItem()
        {
            return await MsProjectRepository.GetProjectSelectItem();
        }

        /// <summary>
        /// 获取首页项目统计数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<ProjectForHome>> GetProjectForHome()
        {
            return await MsProjectRepository.GetProjectForHome();
        }

        /// <summary>
        /// 检查项目是否已存在
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        private async Task<bool> ProjectIsExist(string Name)
        {
            if (string.IsNullOrEmpty(Name))
            {
                return false;
            }

            return await MsProjectRepository.AnyAsync(p => p.Name == Name && !p.IsDeleted);
        }

        /// <summary>
        /// 比较项目的楼栋是否已经创建了任务，楼栋的必须存在，且楼栋、楼层、户数、是否精装不能改变
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> CheckExsitedTask(MsProjectDto model)
        {
            return false;
        }

        /// <summary>
        /// 检查是否存在同名的其它项目
        /// </summary>
        /// <param name="ProjectId"></param>
        /// <param name="Name"></param>
        /// <returns></returns>
        public async Task<bool> ProjectIsExistNotSelf(Guid ProjectId, string Name)
        {
            if (ProjectId == Guid.Empty)
                throw new OperationException("YB0098".SLocalize());
            if (!string.IsNullOrEmpty(Name))
            {
                return await MsProjectRepository.AnyAsync(p => p.Name == Name && p.ProjectId != ProjectId && !p.IsDeleted);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 给用户分配项目
        /// </summary>
        /// <param name="viewmodel"></param>
        /// <returns></returns>
        public async Task<bool> SaveUserToProject(UserProjectViewModel viewmodel)
        {
            var projectCreatorId = await GetProjectCreator(viewmodel.ProjectId);
            var oldUserInProjectList = await MsUserToProjectRepository.WhereAsync(w => w.YunProjectGuid == viewmodel.ProjectId);
            var newAllUserInProject = viewmodel.UserIdList.Select(w => new MsUserToProject()
            {
                CreatedBy = OperatorProvider.Get().Id,
                CreatedDate = DateTime.Now,
                YunUserGuid = w,
                YunProjectGuid = viewmodel.ProjectId
            }).ToList();
            // 新增加的用户
            var newUserInProjectExceptCreatorList = newAllUserInProject.Where(i => i.YunUserGuid != projectCreatorId).Select(w => w).ToList();
            newUserInProjectExceptCreatorList.ForEach(
                (i) =>
                {
                    var oldUserInProjectItem = oldUserInProjectList.Where(oui => oui.YunUserGuid == i.YunUserGuid).Select(oui => oui).FirstOrDefault();
                    if (oldUserInProjectItem == null)
                        i.IsSendMessage = false;
                    else
                        i.IsSendMessage = true;
                });
            //剔除创建者 取消分配的用户
            var oldUserInProjectExceptCreatorList = oldUserInProjectList.Where(w => w.YunUserGuid != projectCreatorId);

            #region 删除除创建者外的该项目的所有人员，并且新增新的人员

            MsUserToProjectRepository.UpdateToDeleteRange(oldUserInProjectExceptCreatorList);
            MsUserToProjectRepository.AddRange(newUserInProjectExceptCreatorList);
            var project = await MsProjectRepository.FirstOrDefaultAsync(i => i.ProjectId == viewmodel.ProjectId).ConfigureAwait(false);
            var needToCleanCacheUserList = oldUserInProjectExceptCreatorList
                .Select(i => i.YunUserGuid)
                .Union(newUserInProjectExceptCreatorList.Select(i => i.YunUserGuid)
                ).Distinct();
            var userIinfo = await SysUserRepository.WhereAsync(i => needToCleanCacheUserList.Contains(i.YunUserGuid)).ConfigureAwait(false);

            #endregion 删除除创建者外的该项目的所有人员，并且新增新的人员

            var reslut = await UnitOfWork.SaveChangesAsync();

            #region 发送短信

            await UserToProjectMessageService.SetUserToProjectSendMessageLogic(
                oldUserInProjectList.Where(w => w.YunUserGuid != projectCreatorId).ToList(),
                newUserInProjectExceptCreatorList,
                viewmodel.IP, userIinfo, project);

            #endregion 发送短信

            #region 需要清除所有用户信息缓存

            foreach (var item in needToCleanCacheUserList)
            {
                await RedisHelper.Instance.StringDeleteAsync(RedisKeyConstant.ProjectVersionKey(item));
            }

            #endregion 需要清除所有用户信息缓存

            return reslut > 0;
        }

        /// <summary>
        /// 保存项目人员关系
        /// </summary>
        /// <returns></returns>
        public async Task SaveProjectUser(UserProjectViewModel viewmodel)
        {
            if (viewmodel.UserIdList.Count < 1)
                throw new OperationException("YB0116".SLocalize());

            var creator = await GetProjectCreator(viewmodel.ProjectId);
            var oldList = await SysUserProjectRepository.WhereAsync(w => w.ProjectId == viewmodel.ProjectId);

            var insertList = viewmodel.UserIdList.Select(w => new SysUserProject()
            {
                UserProjectId = Guid.NewGuid(),
                UserId = w,
                ProjectId = viewmodel.ProjectId
            });
            //剔除创建者
            oldList.RemoveAll(w => w.UserId == creator);
            await UnitOfWork.OpenTrans(async (save) =>
             {
                 //清除历史人员数据
                 SysUserProjectRepository.UpdateToDeleteRange(oldList);
                 await save();
                 //保存新的项目人员数据
                 SysUserProjectRepository.AddRange(insertList);
             });
            //清除项目成员缓存
            MsTaskRepository.RemoveUserProjects();
            //await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 人员项目关系重复判断
        /// </summary>
        /// <param name="UserId"></param>
        /// <param name="ProjectId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<bool> UserProjectIsExist(Guid UserId, Guid ProjectId)
        {
            if (UserId == Guid.Empty || ProjectId == Guid.Empty)
                throw new OperationException("YB0117".SLocalize());
            return await SysUserProjectRepository.AnyAsync(p => p.UserId == UserId && p.ProjectId == ProjectId
                                                                                   //&& !p.IsDeleted
                                                                                   );
        }

        /// <summary>
        /// 获取项目创建人
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<Guid> GetProjectCreator(Guid projectId)
        {
            var project = await MsProjectRepository.GetByIdAsync(projectId);
            if (project == null)
                throw new OperationException("YB0117".SLocalize());
            return project.CreatedBy;
        }

        /// <summary>
        /// 获取项目信息树-项目-楼栋-楼层-户型
        /// </summary>
        /// <returns></returns>
        public async Task<TreeNodeDto[]> GetProjectInfoTree()
        {
            TreeNodeDto[] projectNodes = null;
            Guid userId = OperatorProvider.Get().Id;
            var apiPageResult = await UserProjectService.GetPage(new SysUserProjectCondition() { UserId = userId, PageSize = int.MaxValue, IsDeleted = false, OrderBy = "LastUpdatedDate desc" });
            if (apiPageResult != null && apiPageResult.PageData != null)
            {
                var userProjects = apiPageResult.PageData as List<SysUserProjectDto>;

                if (userProjects != null && userProjects.Count > 0)
                {
                    projectNodes = new TreeNodeDto[userProjects.Count];

                    for (int i = 0; i < userProjects.Count; i++)//项目
                    {
                        var pro = userProjects[i];
                        projectNodes[i] = new TreeNodeDto();
                        var proNode = projectNodes[i];
                        proNode.name = pro.ProjectName;
                        proNode.id = pro.ProjectId.ToString();
                        proNode.Depth = 0;
                        proNode.fullPath = proNode.name; ;
                        if (!String.IsNullOrWhiteSpace(pro.Details))
                        {
                            var detailsList = JsonConvert.DeserializeObject<List<Detail>>(pro.Details);
                            if (detailsList != null && detailsList.Count > 0)
                            {
                                proNode.children = new List<TreeNodeDto>();

                                for (int j = 0; j < detailsList.Count; j++)//楼栋
                                {
                                    var buildNo = detailsList[j].Building;
                                    TreeNodeDto buildNode = new TreeNodeDto();
                                    buildNode.Depth = 1;
                                    buildNode.id = "build-" + j;
                                    buildNode.name = buildNo + "栋";
                                    buildNode.fullPath = proNode.fullPath + "-" + buildNode.name;
                                    buildNode.SupportStandard = detailsList[j].Standard;                  // 交付标准
                                    var buildFloors = detailsList.Where(p => p.Building == buildNo).Select(p => new { p.Floor }).Distinct().OrderBy(p => p.Floor).ToList();

                                    if (buildFloors != null && buildFloors.Count > 0)
                                    {
                                        buildNode.children = new List<TreeNodeDto>();
                                        for (int k = 0; k < buildFloors.Count; k++)//楼层
                                        {
                                            var floorInfo = buildFloors[k];
                                            var floor = floorInfo.Floor.ToInt32();

                                            for (int k1 = 1; k1 <= floor; k1++)//从第一层到floorNo层
                                            {
                                                TreeNodeDto floorNode = new TreeNodeDto();
                                                floorNode.Depth = 2;
                                                floorNode.name = k1 + "层";
                                                floorNode.id = $"{proNode.id}-{buildNode.id}-{k1}";
                                                floorNode.fullPath = buildNode.fullPath + "-" + floorNode.name;
                                                floorNode.SupportStandard = buildNode.SupportStandard;   // 交付标准
                                                buildNode.children.Add(floorNode);

                                                var houseHoldsList = detailsList.Where(
                                                    p => p.Building == buildNo
                                                 && p.Floor == floorInfo.Floor)
                                                    .Select(p => new { p.HouseHolds })
                                                    .Distinct()
                                                    .OrderBy(p => p.HouseHolds)
                                                    .ToList();
                                                if (houseHoldsList != null && houseHoldsList.Count > 0)
                                                {
                                                    floorNode.children = new List<TreeNodeDto>();
                                                    for (int l = 0; l < houseHoldsList.Count; l++)
                                                    {
                                                        var houseHold = houseHoldsList[l];

                                                        for (int m = 0; m < houseHold.HouseHolds.ToInt32(); m++)
                                                        {
                                                            TreeNodeDto houseHoldNode = new TreeNodeDto();
                                                            houseHoldNode.Depth = 3;
                                                            var houseHoldNo = m + 1;
                                                            houseHoldNode.name = (k1 < 10 ? "0" : "") + k1 + (houseHoldNo < 10 ? "0" : "") + houseHoldNo;
                                                            houseHoldNode.id = $"{proNode.id}-{buildNode.id}-{k1}-{l}-{houseHoldNo}";
                                                            houseHoldNode.fullPath = floorNode.fullPath + "-" + houseHoldNode.name;
                                                            houseHoldNode.SupportStandard = buildNode.SupportStandard;  // 交付标准
                                                            floorNode.children.Add(houseHoldNode);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    proNode.children.Add(buildNode);
                                }
                            }
                        }
                    }
                }
            }

            return projectNodes;
        }

        /// <summary>
        /// 获取当前所有有效的站点类型
        /// </summary>
        /// <returns></returns>
        public async Task<List<MsPointType>> GetAllPonitTypes(Guid projectId)
        {
            return await MsPointTypeRepository.WhereAsync(i => i.ProjectGuid == projectId && i.IsDeleted == false).ConfigureAwait(false);
        }

        /// <summary>
        /// 逻辑删除任务类型
        /// </summary>
        /// <param name="id"></param>
        /// <param name="projectid"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task RemovePonitTypes(Guid id, Guid projectid)
        {
            var houseMaps = await MsHouseMapRepository.GetHouseMapByPointType(new HouseMapCondition { MsPointTypeId = id, ProjectGuid = projectid }); ;
            if (houseMaps != null && houseMaps.Count > 0)
            {
                throw new OperationException("YB0133".SLocalize());
            }

            var points = await MsPointTypeRepository.GetTaskPointsByType(id, projectid);
            if (points != null && points.Count > 0)
            {
                throw new OperationException("YB0133".SLocalize());
            }
            var mpt = await MsPointTypeRepository.GetListByProjectId(projectid);
            var project = MsProjectRepository.GetById(projectid);
            if (mpt != null)
            {
                var entity = mpt.Where(i => i.Id == id).FirstOrDefault();
                var name = entity.Name;
                entity.Name = $"{entity.Name}-{id.ToString().Substring(id.ToString().Length - 4, 4)}";    // 删除时修改名字
                entity.SetOperatorInfoWhenRemove();
                Guid oldId = entity.Id;
                entity.Id = Guid.NewGuid();
                MsPointTypeRepository.Update(entity, x => new { x.Id, x.IsDeleted, x.Name, x.LastUpdatedBy, x.LastUpdatedDate });
                var soureProjectAllPointTypeMeasureItems = await MsPointTypeMeasureItemRepository.GetDataByProjects(new Guid[] { projectid });
                soureProjectAllPointTypeMeasureItems = soureProjectAllPointTypeMeasureItems.Where(i => i.MsPointTypeId == oldId).ToList();
                foreach (var item in soureProjectAllPointTypeMeasureItems)
                {
                    item.MsPointTypeId = entity.Id;
                    MsPointTypeMeasureItemRepository.Update(item, x => new { x.MsPointTypeId });
                }
                MsProjectRepository.UpdateProjectVersion(projectid);
                MsProjectEditLogRepository.Add(new MsProjectEditLog
                {
                    ProjectId = projectid,
                    ProjectName = project?.Name,
                    CreatedBy = OperatorProvider.Get().YunUserGuid,
                    CreatedDate = DateTime.Now,
                    EditLogId = Guid.NewGuid(),
                    EditType = MsProjectEditTypeEnum.标准库.ToString(),
                    IsDeleted = false,
                    IsPublished = true,
                    ChangeLog = $"删除标准库类型：{name}"
                });
                await UnitOfWork.SaveChangesAsync();
            }
            else
            {
                throw new OperationException("YB0134".SLocalize());
            }
        }

        /// <summary>
        /// 保存站点类型
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectGuid"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task SavePointType(string name, Guid projectGuid)
        {
            if (await MsPointTypeRepository.AnyAsync(i => i.Name == name && i.ProjectGuid == projectGuid && !i.IsDeleted))
            {
                throw new OperationException("YB0135".SLocalize(name));
            }
            int type = await MsPointTypeRepository.GetMaxType(projectGuid);
            var model = new MsPointType()
            {
                Id = Guid.NewGuid(),
                Name = name,
                Type = type,
                ProjectGuid = projectGuid,
            };

            var standards = await MsProjectStandardRepository.WhereAsync(i => i.ProjectGuid == projectGuid);
            List<MsPointTypeMeasureItem> pointTypeMeasureItems = new List<MsPointTypeMeasureItem>();

            var measureItemList = await MsProjectStandardMeasureItemRepository.WhereAsync(x => x.ProjectGuid == projectGuid
                                                                            && standards.Select(y => y.ProjectStandardId).Contains(x.ProjectStandardId));

            var companyGuid = OperatorProvider.Get().CompanyGuid;
            // 获取模板值
            var pointTypeMeasureItemsData = await MsPointTypeMeasureItemRepository.GetAll().Where(x => x.ProjectGuid == Guid.Empty || x.ProjectGuid == projectGuid).AsNoTracking().Select(x => new { x.ProjectStandardId, x.Id, x.IsChecked, x.MsPointTypeId }).ToListAsync();

            measureItemList.ForEach(measureItem =>
            {
                var isChecked = pointTypeMeasureItemsData.FirstOrDefault(x => x.ProjectStandardId == measureItem.ProjectStandardId && x.IsChecked && (x.Id == measureItem.Id || (x.MsPointTypeId == model.Id)))?.IsChecked;
                pointTypeMeasureItems.Add(new MsPointTypeMeasureItem
                {
                    ProjectStandardId = measureItem.ProjectStandardId,
                    Id = measureItem.Id,
                    MsPointTypeId = model.Id,
                    // 设置每个项目阶段默认选中测量项
                    IsChecked = isChecked ?? false,
                    ProjectGuid = projectGuid,
                    CompanyGuid = companyGuid,
                    MsPointTypeMeasureItemId = Guid.NewGuid()
                });
            });

            MsPointTypeMeasureItemRepository.AddRange(pointTypeMeasureItems);
            model.SetOperatorInfoWhenAdd();
            MsPointType model2 = await MsPointTypeRepository.GetPointType(name, projectGuid);
            if (model2 != null && !string.IsNullOrWhiteSpace(model2.Name))
            {
                throw new OperationException("YB0135".SLocalize(name));
            }
            MsPointTypeRepository.Add(model);
            MsProjectRepository.UpdateProjectVersion(projectGuid);
            var project = MsProjectRepository.GetById(projectGuid);
            MsProjectEditLogRepository.Add(new MsProjectEditLog
            {
                ProjectId = projectGuid,
                ProjectName = project?.Name,
                CreatedBy = OperatorProvider.Get().YunUserGuid,
                CreatedDate = DateTime.Now,
                EditLogId = Guid.NewGuid(),
                EditType = MsProjectEditTypeEnum.标准库.ToString(),
                IsDeleted = false,
                IsPublished = true,
                ChangeLog = $"增加标准库类型：{model.Name}"
            });
            await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 获取站点类型详情
        /// </summary>
        /// <param name="projectStandardId"></param>
        /// <param name="PrjectGuid"></param>
        /// <returns></returns>
        public async Task<List<MsPointTypeDto>> GetPointTypeDetails(Guid projectStandardId, Guid PrjectGuid)
        {
            return await MsPointTypeRepository.GePointTypeDetail(projectStandardId, Guid.Empty, PrjectGuid);
        }

        /// <summary>
        /// 作者：黄钧航
        /// 提供FMS-获取所有项目信息
        /// </summary>
        /// <returns></returns>
        public async Task<List<ProjectAddressDto>> GetAllProjects()
        {
            string sql = string.Format(@"SELECT
	                                        T1.""DeviceNumber"",
	                                        T1.""DeviceGuid"",
	                                        T2.""YunUserGuid"",
	                                        T2.""Name"",
	                                        T4.""ProjectId"",
	                                        T4.""ProjectNo"",
	                                        T4.""Name"" AS ProjectName,
	                                        T4.""Province"",
	                                        T4.""Town"",
	                                        T4.""City"",
	                                        T4.""Address""
                                        FROM
	                                        ""SysDevice"" T1
	                                        INNER JOIN ""SysUser"" T2 ON T1.""DeviceUserId"" = T2.""YunUserGuid""
	                                        INNER JOIN ""MsUserToProject"" T3 ON T3.""YunUserGuid"" = T2.""YunUserGuid""
	                                        INNER JOIN ""MsProject"" T4 ON T4.""ProjectId"" = T3.""YunProjectGuid""
                                        WHERE
	                                        T4.""IsDeleted"" = FALSE
	                                        AND T1.""IsDeleted"" = FALSE
                                        ORDER BY
	                                        T1.""DeviceNumber"" DESC");

            var projectList = new List<ProjectAddressDto>();
            var addressList = await PgSqlHelper.QueryListAsync<ProjectAddressDto>(sql);

            foreach (var item in addressList)
            {
                var existed = projectList.Find(x => x.ProjectId == item.ProjectId);
                if (existed == null)
                {
                    existed = item;
                    projectList.Add(existed);
                };

                existed?.Devices.Add(new DeviceInfo()
                {
                    Id = item.DeviceGuid.ToString(),
                    Name = item.DeviceNumber,
                });
            }

            return projectList;
        }

        /// <summary>
        /// 分页获取项目列表
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<ApiPageResult> GetProjectWithReportPage(MsProjectCondition condition)
        {
            return await MsProjectRepository.GetProjectWithReportList(condition);
        }
    }
}